package cn.turboinfo.fuyang.api.provider.mini.service.impl.wechat;

import cn.turboinfo.fuyang.api.domain.common.service.wechat.WechatService;
import cn.turboinfo.fuyang.api.entity.common.fo.wechat.WechatAuthResult;
import cn.turboinfo.fuyang.api.entity.common.fo.wechat.WechatGetPhoneResult;
import cn.turboinfo.fuyang.api.entity.common.fo.wechat.WechatGetTokenResult;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.val;
import okhttp3.*;
import okhttp3.logging.HttpLoggingInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


@RequiredArgsConstructor
@Service
public class MiniWechatServiceImpl implements WechatService {

    @Value("${kit.wechat.mini.api:}")
    private String miniApi;

    @Value("${kit.wechat.mini.app-id:}")
    private String appId;

    @Value("${kit.wechat.mini.app-secret:}")
    private String appSecret;

    private final OkHttpClient okHttpClient;

    private final ObjectMapper objectMapper;

    private OkHttpClient buildOkHttpClient() {
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);

        return new OkHttpClient.Builder()
                .connectTimeout(5, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .addInterceptor(logging)
                // 不验证证书
                .hostnameVerifier((hostname, session) -> true)
                .build();
    }

    private ObjectMapper buildObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();

        objectMapper
                .setSerializationInclusion(JsonInclude.Include.NON_NULL)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        return objectMapper;
    }

    public MiniWechatServiceImpl() {

        this.okHttpClient = buildOkHttpClient();
        this.objectMapper = buildObjectMapper();
    }

    @Override
    public WechatAuthResult auth(String code) throws IOException {
        String url = miniApi + "/sns/jscode2session?appid=" + appId + "&secret=" + appSecret + "&js_code=" + code + "&grant_type=authorization_code";

        Request request = new Request.Builder()
                .url(url)
                .get()
                .header("Content-Type", "application/json;charset=UTF-8")
                .build();

        Call call = okHttpClient.newCall(request);

        Response response = call.execute();
        val dataStr = response.body().string();
        WechatAuthResult result = null;
        try {
            if (response.body() != null) {
//                result = JSONObject.parseObject(dataStr, WechatAuthResult.class);
                result = objectMapper.readValue(dataStr, WechatAuthResult.class);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public WechatGetPhoneResult getPhone(String code) throws IOException {
        String accessToken = this.getAccessToken();

        Map<String, String> map = new HashMap<>();
        map.put("code", code);


        String url = miniApi + "/wxa/business/getuserphonenumber?access_token=" + accessToken;

        objectMapper.writer().writeValueAsString(code);

        Request request = new Request.Builder()
                .url(url)
                .post(RequestBody.create(MediaType.parse("application/json"), objectMapper.writeValueAsString(map)))
                .header("Content-Type", "application/json;charset=UTF-8")
                .build();

        Call call = okHttpClient.newCall(request);

        Response response = call.execute();
        if (response.body() != null) {
            return objectMapper.readValue(response.body().string(), WechatGetPhoneResult.class);
        } else {
            throw new RuntimeException("获取手机号失败");
        }
    }

    private String getAccessToken() throws IOException {
        String url = miniApi + "/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;

        Request request = new Request.Builder()
                .url(url)
                .get()
                .header("Content-Type", "application/json;charset=UTF-8")
                .build();

        Call call = okHttpClient.newCall(request);

        Response response = call.execute();
        WechatGetTokenResult result = null;
        try {

            if (response.body() != null) {
                val dataStr = response.body().string();
                result = objectMapper.readValue(dataStr, WechatGetTokenResult.class);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (result == null) {
            throw new RuntimeException("获取access_token失败");
        }

        return result.getAccess_token();
    }
}
